/**
 * 
 */
package com.skivingcloud.workflow.service.impl;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.activiti.bpmn.model.FormProperty;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.NativeHistoricProcessInstanceQuery;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.NativeUserQuery;
import org.activiti.engine.impl.RuntimeServiceImpl;
import org.activiti.engine.impl.persistence.entity.CommentEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.runtime.ProcessInstanceBuilderImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.IdentityLinkType;
import org.activiti.engine.task.NativeTaskQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.skivingcloud.admin.sys.entity.User;
import com.skivingcloud.common.exception.BusinessException;
import com.skivingcloud.common.utils.BeanMapUtil;
import com.skivingcloud.common.utils.DateUtils;
import com.skivingcloud.common.utils.ObjectUtils;
import com.skivingcloud.common.utils.PageUtils;
import com.skivingcloud.common.utils.StringUtils;
import com.skivingcloud.workflow.cmd.RollbackTaskCmd;
import com.skivingcloud.workflow.conf.WorkflowContants;
import com.skivingcloud.workflow.mapper.*;
import com.skivingcloud.workflow.entity.Delegation;
import com.skivingcloud.workflow.entity.HistoryProcessVo;
import com.skivingcloud.workflow.entity.StrategyQueryVo;
import com.skivingcloud.workflow.entity.TaskParam;
import com.skivingcloud.workflow.entity.TaskVO;
import com.skivingcloud.workflow.entity.Strategy;
import com.skivingcloud.workflow.service.IDelegationService;
import com.skivingcloud.workflow.service.IStrategyService;
import com.skivingcloud.workflow.service.LovelyTaskService;
import com.skivingcloud.workflow.service.ModelService;

import net.sf.json.JSONObject;

/**
 * @author hushouquan
 *
 */
@Service
public class LovelyTaskServiceImpl implements LovelyTaskService {

	@Autowired
    private RepositoryService repositoryService;
	@Autowired
    private RuntimeService runtimeService;
	@Autowired
    private TaskService taskService;
	@Autowired
	private IStrategyService strategyService;
	@Autowired
	private RestTemplate restTemplate;
	@Autowired
    private HistoryService historyService;
	@Autowired
    private IdentityService identityService;
	@Autowired
    private FormService formService;
	@Autowired
    private WfCommonMapper wfCommonMapper;
	@Autowired
    private ModelService modelService;
	@Autowired
	private ManagementService managerService;
	@Autowired
    private IDelegationService delegationService;
	
	/**
	 * 流程提交方法
	 * @param params 参数
	 * @param user 操作人
	 * @return
	 */
	@Override
	public TaskParam subminTask(TaskParam params, User user) {
        Map<String, Object> variables = new HashMap<>();
		//创建任务
        if (params.getTaskId() == null || "".equals(params.getTaskId())) {
        	List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey(params.getProcessKey()).latestVersion().list();
        	if(list.isEmpty()) {
        		throw new BusinessException("没有找到相关流程定义");
        	}
        	ProcessInstanceBuilderImpl builder = new ProcessInstanceBuilderImpl((RuntimeServiceImpl)runtimeService);
            builder.businessKey(params.getBusNo());
            //优先使用参数中的租户，没有就使用当前操作人的租户，在没有就使用流程定义的租户，再没有就没办法了
            String tenantId = params.getTenantId() == null ? user.getTenantId() : params.getTenantId();
        	builder.tenantId(tenantId == null ? list.get(0).getTenantId() : tenantId);
        	if (params.getBriefReport() != null && !"".equals(params.getBriefReport())) {
                builder.processInstanceName(params.getBriefReport().toString());
        	} else {
        		builder.processInstanceName(list.get(0).getName() + "-" + user.getStaffName()+ "-" +DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
        	}
        	builder.processDefinitionId(list.get(0).getId());
        	builder.processDefinitionKey(params.getProcessKey());
        	params.wf_param.put("startUserId", params.getUser().getId());

            variables.put("wf_param", params.wf_param);//放入流程参数

            variables.putAll(params.wf_param);

            variables.put("wf_allUserID", params.getUser().getId());//放入参与人ID

            variables.put("wf_startUserName", params.getUser().getStaffName());//放入参与人姓名，用于模糊查询
            variables.put("formProperties", params.getFormProperties());
        	builder.getVariables().putAll(variables);
        	builder.addVariable("wf_startUserId", params.getUser().getId());
        	//设置流程发起人,设置该流程启动人是和当前线程绑定的，所以线程应该是安全的
        	identityService.setAuthenticatedUserId(params.getUser().getId());
        	ProcessInstance instance = builder.start();//启动流程
        	identityService.setAuthenticatedUserId(null);
        	params.setInsId(instance.getProcessInstanceId());
        	if(!params.isSkipFirstNode()) {
        		Set<String> allCandidateUser = new HashSet<String>();
        		List<Task> tasks = taskService.createTaskQuery().processInstanceId(instance.getProcessInstanceId()).list();
                for (Task task : tasks) {
                    task.setTenantId(builder.getTenantId());
                    taskService.saveTask(task);
                    allCandidateUser.addAll(addCandidateUser(params.getUser().getId(), task));
                }
        	}else {
        		List<Task> tasks = taskService.createTaskQuery().processInstanceId(instance.getProcessInstanceId()).list();
        		for (Task task : tasks) {
                    task.setTenantId(builder.getTenantId());
                    //处理结果设置为发起
                    task.setDescription(WorkflowContants.ProcessResult.START.getValue());
                    taskService.saveTask(task);
                    taskService.addComment(task.getId(), task.getProcessInstanceId(), params.getDiscicription() != null ? params.getDiscicription() : "发起流程");
                    taskService.addUserIdentityLink(task.getId(), params.getUser().getId(), IdentityLinkType.STARTER);
                    taskService.setAssignee(task.getId(), params.getUser().getId());
                    taskService.complete(task.getId());
                }
        		Set<String> allCandidateUser = new HashSet<String>();
        		//获取新任务，重新设置审批人
                List<Task> newtasks = taskService.createTaskQuery().processInstanceId(instance.getProcessInstanceId()).list();
                for (Task task : newtasks) {
                    allCandidateUser.addAll(addCandidateUser(params.getUser().getId(), task));
                }
        	}
        } else {
        	taskService.claim(params.getTaskId(), params.getUser().getId());//检出任务
        	if("1".equals(params.getAuthCatagory())){
                //如果是代理的情况，把拥有者改为授权人
                taskService.setOwner(params.getTaskId(), params.getOwner());
            }
        	taskService.setVariables(params.getTaskId(), params.wf_param);
        	taskService.setVariablesLocal(params.getTaskId(), params.getVariablesLocal());
        	taskService.setVariableLocal(params.getTaskId(), "formProperties", params.getFormProperties());
        	Task taskOld = taskService.createTaskQuery().taskId(params.getTaskId()).singleResult();
        	taskOld.setDescription(params.getApproveAdvice());
        	taskService.saveTask(taskOld);
        	taskService.addComment(taskOld.getId(), taskOld.getProcessInstanceId(), params.getDiscicription());
        	params.setInsId(taskOld.getProcessInstanceId());
        	taskService.complete(taskOld.getId());
        	//有需求要更新流程摘要
            if (params.getBriefReport() != null && !"".equals(params.getBriefReport())){
                runtimeService.setProcessInstanceName(taskOld.getProcessInstanceId(), params.getBriefReport().toString());
            }
            List<Task> newtasks = taskService.createTaskQuery().processInstanceId(params.getInsId()).list();
            HistoricProcessInstance hProcessInstance = historyService.createHistoricProcessInstanceQuery().unfinished().
                    processInstanceId(params.getInsId()).singleResult();
            Set<String> allCandidateUser = new HashSet<String>();
            for (Task newtask : newtasks) {
                allCandidateUser.addAll(addCandidateUser(hProcessInstance.getStartUserId(), newtask));
            }
        }
		return params;
	}

	/**
     * <p>重新设置候选人，把策略，岗位对应的用户查询出来设置进去</p>
     * <p>Description: </p>
     *  @param startUserId 发起人
     * @param task 任务
     * @return 待办人员
     */
    private Set<String> addCandidateUser(String startUserId, Task task) {
        //返回待办人员
        Set<String> allCandidateUser = new HashSet<String>();
        // 查询流程相关人员（候选人、岗位）
        List<IdentityLink> identityLinkList = taskService.getIdentityLinksForTask(task.getId());
        // 所有有效的策略
        List<String> candidateGroupIdExpressions = new ArrayList<String>();
        List<String> stationIds = new ArrayList<String>();
        for (IdentityLink identityLink : identityLinkList) {
            //如果identityLink.getType()为candidate且identityLink.getGroupId()没值说明该相关人员为候选人
            if (IdentityLinkType.CANDIDATE.equals(identityLink.getType())) {
                if (identityLink.getGroupId() == null || "".equals(identityLink.getGroupId().trim())) {
                    //判断这个id是否为用户id，如果是则不作处理，不是证明是策略，那么去执行这个策略找出相关人员再把人员添加到候选人当中去
                    if (!isUser(identityLink.getUserId())) {
                        //List<String> listCandidate = getListCandidateByStrategyId(startUserId,identityLink.getUserId());
                        candidateGroupIdExpressions.add(identityLink.getUserId());
                    }else{
                        allCandidateUser.add(identityLink.getUserId());
                    }
                } else {
                    stationIds.add(identityLink.getGroupId());
                }

            }
        }
        if (candidateGroupIdExpressions.isEmpty() && stationIds.isEmpty()) {
            //没有策略和岗位，什么也不做
        } else {
            StrategyQueryVo strategyQueryVo = new StrategyQueryVo();
            strategyQueryVo.setWf_param(taskService.getVariables(task.getId()));
            strategyQueryVo.setStationIds(stationIds);
            strategyQueryVo.setCandidateGroupIdExpressions(candidateGroupIdExpressions);
            List<Map<String, Object>> users = getApproverLst(startUserId, strategyQueryVo);

            for (Map<String, Object> map : users) {
                taskService.addCandidateUser(task.getId(), map.get("userId").toString());
                allCandidateUser.add(map.get("userId").toString());
            }
        }
        return allCandidateUser;
    }
    
    /**
     * <p>判断id是否为用户</p>
     * <p>Description: </p>
     *
     * @param userId
     * @return
     */
    private boolean isUser(String userId) {
    	// String querySql = "select ID_,FIRST_,LAST_ from ACT_ID_USER WHERE ID_='" + userId + "'";
        org.activiti.engine.identity.User user = identityService.createUserQuery().userId(userId).singleResult();
        // List<Map<String, Object>> list_result = sqlAdapterMapper.selectSQL(querySql);
        if (user != null) {
            return true;
        }
        return false;
    }
    
    /**
     * <p>根据策略返回去重后的候选人</p>
     * <p>Description: </p>
     *
     * @param startUserId
     * @param strategyQueryVo
     * @return
     */
    private List<Map<String, Object>> getApproverLst(String startUserId, StrategyQueryVo strategyQueryVo) {
        List<Map<String, Object>> approverLst = new ArrayList<Map<String, Object>>();
        
        try {

            List<Map<String, Object>> list = new ArrayList<>();
            Map<String, Object> wf_param = strategyQueryVo.getWf_param();
            String excludeSponsorId = "";

            // 通过找人策略ID获取策略信息
            List<String> strategys = strategyQueryVo.getCandidateGroupIdExpressions();

            if (strategys != null) {

                for (String findUserId : strategys) {
                    Strategy strategy = strategyService.selectById(findUserId);
                    if ("3".equals(strategy.getStrategyType())) {
                        //服务调用策略
                        //把sql串当中参数传给接口，sql串可定义为json,例如{pra1:${par1},par2:${par2}}
                        String sql = strategy.getStrategySql();
                        String[] params = strategy.getStrategyParam() != null ? strategy.getStrategyParam().split(",") : new String[0];
                        for (String p : params) {
                            String p_value = wf_param.get(p) != null ? wf_param.get(p).toString() : "";
                            String regx = "\\$\\{" + p + "\\}";
                            sql = sql.replaceAll(regx, p_value);
                        }
                        ResponseEntity<String[]> res = restTemplate.postForEntity("http://" + strategy.getServerName() + strategy.getApiUrl(), sql, String[].class);
                        //这里已经改为直接返回用户Id了
                        String[] userIds = res.getBody();
                        StringBuffer inPram = new StringBuffer();
                        for (String ss : userIds) {
                            inPram.append("'" + ss + "',");
                        }
                        String inp = inPram.toString().substring(0, inPram.toString().length() - 1);
                        String querySql = "select ID_ as \"userId\",FIRST_,LAST_ as username from ACT_ID_USER WHERE ID_ in(" + inp + ")";
                        List<Map<String, Object>> list_result = wfCommonMapper.selectSQL(querySql);
                        list.addAll(list_result);
                    } else if ("1".equals(strategy.getStrategyType())) {
                        //发起人策略
                        if ("sponsor".equals(strategy.getStrategyCode())) {
//                            User user = fSysUserAuthService.getUserById(startUserId);
                            String querySql = " select ID_ as \"userId\",FIRST_,LAST_ as username from ACT_ID_USER WHERE ID_ ='" + startUserId + "'";
                            List<Map<String, Object>> list_result = wfCommonMapper.selectSQL(querySql);
                            list.addAll(list_result);
                        } else if ("excludeSponsor".equals(strategy.getStrategyCode())) {
                            //除发起人
                            excludeSponsorId = startUserId;
                        } else {
                            //待扩展
                        }
                    } else if ("2".equals(strategy.getStrategyType())) {
                        String sql = strategy.getStrategySql();
                        String[] params = strategy.getStrategyParam() != null ? strategy.getStrategyParam().split(",") : new String[0];
                        for (String p : params) {
                            String p_value = wf_param.get(p) != null ? wf_param.get(p).toString() : "";
                            String regx = "\\$\\{" + p + "\\}";
                            sql = sql.replaceAll(regx, p_value);
                        }
                        // 通过策略sql获取审批人列表
                        List<Map<String, Object>> list_result = wfCommonMapper.selectSQL(sql);
                        list.addAll(list_result);
                    } else {
                        //待扩展
                    }
                }
            }

            //通过岗位筛选
            List<String> stationIds = strategyQueryVo.getStationIds();

            String selectStationUser = "select suser.ID_ as \"userId\",suser.LAST_ as username,station.NAME_ as station_name,station.ID_ from ACT_ID_USER suser,ACT_ID_MEMBERSHIP stationuser,ACT_ID_GROUP station where suser.ID_=stationuser.USER_ID_ and station.ID_=stationuser.GROUP_ID_ and station.ID_='#{station_id}'";

            if (stationIds != null) {
                for (String stationId : stationIds) {
                    List<Map<String, Object>> list_result = wfCommonMapper.selectSQL(selectStationUser.replace("#{station_id}", stationId));
                    list.addAll(list_result);
                }
            }

            //审批人去重（借用Map的Key排他性）
            Map approveMap = new HashMap<String, Object>();
            for (Map usr : list) {
                if (excludeSponsorId.equals(usr.get("userId").toString())) continue;//除发起人
                approveMap.put(usr.get("userId").toString(), usr);
            }

            Iterator<Map.Entry<String, Map>> iterator = approveMap.entrySet().iterator();
            for (; iterator.hasNext(); ) {
                Map.Entry<String, Map> entry = iterator.next();
                approverLst.add(entry.getValue());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return approverLst;
    }

	@Override
	public PageUtils getToDoList(Map<String, Object> params, User user) {
		int page = Integer.parseInt(params.get("page") != null ? params.get("page").toString() : "0");
        int limit = Integer.parseInt(params.get("limit") != null ? params.get("limit").toString() : "0");
        String[] tenantIds = params.get("tenantIds") != null ? params.get("tenantIds").toString().split(",") : null;
        String[] processNames = params.get("processName") != null ? params.get("processName").toString().split(",") : null;
        String userId = user.getId();
        //List<Task> tasks = WorkFlowExecution.taskService.createTaskQuery().taskAssigneeLikeIgnoreCase("%"+userId+"%").orderByTaskCreateTime().desc().listPage((page - 1) * limit, limit);
        //Long count= WorkFlowExecution.taskService.createTaskQuery().taskAssigneeLikeIgnoreCase("%"+userId+"%").count();
        List<Task> tasks = null;
        Long count = 0L;

        //如果租户ID 不为空，则查询时增加租户ID查询条件
        if (tenantIds != null && tenantIds.length > 0) {
            List<Group> groups = identityService.createGroupQuery().groupMember(userId).list();
            NativeTaskQuery taskQuery = taskService.createNativeTaskQuery();
            NativeTaskQuery taskCountQuery = taskService.createNativeTaskQuery();

            String query_sql = "SELECT DISTINCT RES.* FROM ACT_RU_TASK RES LEFT JOIN ACT_RU_IDENTITYLINK I ON I.TASK_ID_ = RES.ID_ " +
                    "LEFT JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_ WHERE  (RES.ASSIGNEE_ = #{userId} " +
                    "OR (RES.ASSIGNEE_ IS NULL AND I.TYPE_ = 'candidate' AND (I.USER_ID_ = #{userId} or I.GROUP_ID_ IN(select GROUP_ID_ from ACT_ID_MEMBERSHIP WHERE USER_ID_= #{userId})))) ";
            String count_sql = "SELECT COUNT(DISTINCT RES.ID_) FROM ACT_RU_TASK RES LEFT JOIN ACT_RU_IDENTITYLINK I ON I.TASK_ID_ = RES.ID_ " +
                    "LEFT JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_ WHERE (RES.ASSIGNEE_ = #{userId} " +
                    "OR (RES.ASSIGNEE_ IS NULL AND I.TYPE_ = 'candidate' AND (I.USER_ID_ = #{userId} or I.GROUP_ID_ IN(select GROUP_ID_ from ACT_ID_MEMBERSHIP WHERE USER_ID_= #{userId})) )) ";
            String order_sql = " ORDER BY RES.CREATE_TIME_ DESC";

            String base_or_sql = " AND (RES.TENANT_ID_ LIKE CONCAT('%', #{tenantId0}, '%') ";
            //可能传多个租户ID过来
            for (int i = 0; i < tenantIds.length; i++) {
                if (i == 0) {
                    taskQuery.parameter("tenantId0", tenantIds[i]);
                    taskCountQuery.parameter("tenantId0", tenantIds[i]);
                    continue;
                }
                base_or_sql = base_or_sql.concat("OR RES.TENANT_ID_ LIKE CONCAT('%', #{tenantId" + i + "}, '%')");
                taskQuery.parameter("tenantId" + i, tenantIds[i]);
                taskCountQuery.parameter("tenantId" + i, tenantIds[i]);
            }
            base_or_sql = base_or_sql.concat(") ");
            query_sql = query_sql.concat(base_or_sql);
            count_sql = count_sql.concat(base_or_sql);
            //如果流程名称不为空，则增加查询条件
            if (StringUtils.isNotBlank(processNames)) {

                String processName_sql = "AND DEF.NAME_ IN (";
                for (int i = 0; i < processNames.length; i++) {
                    processName_sql = processName_sql.concat("#{processName" + i + "}");
                    if (i != processNames.length - 1) {
                        processName_sql = processName_sql.concat(",");
                    }
                    taskQuery.parameter("processName" + i, processNames[i]);
                    taskCountQuery.parameter("processName" + i, processNames[i]);
                }
                processName_sql = processName_sql.concat(") ");
                query_sql = query_sql.concat(processName_sql);
                count_sql = count_sql.concat(processName_sql);
            }
            tasks = taskQuery.sql(query_sql.concat(order_sql)).parameter("userId", userId).listPage((page - 1) * limit, limit);
            count = taskCountQuery.sql(count_sql).parameter("userId", userId).count();
        } else {
            tasks = taskService.createTaskQuery()
                    .taskCandidateOrAssigned(userId).orderByTaskCreateTime().desc().listPage((page - 1) * limit, limit);
            count = taskService.createTaskQuery().taskCandidateOrAssigned(userId).count();
        }
        List<TaskVO> taskVOS = new LinkedList<TaskVO>();
        for (Task task : tasks) {
            //ProcessInstance  processInstance= WorkFlowExecution.runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            HistoricProcessInstance hProcessInstance = historyService.createHistoricProcessInstanceQuery().unfinished().
                    processInstanceId(task.getProcessInstanceId()).singleResult();

            Map<String, Object> variable = taskService.getVariables(task.getId());
            Map<String, Object> processVariable = runtimeService.getVariables(task.getExecutionId());

            ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
            ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionId(hProcessInstance.getProcessDefinitionId()).singleResult();
            Object returnSign = variable.get("returnSign");
            Map<String, Object> wf_param = (Map<String, Object>) variable.get("wf_param");
            wf_param.putAll(processVariable);
            boolean returnSign_b = returnSign != null ? Boolean.parseBoolean(returnSign.toString()) : false;//是否退回节点
            TaskVO taskVO = new TaskVO(task);

//             User assiginObjec = fSysUserAuthService.getUserById(task.getAssignee());
//             if (assiginObjec!=null) {
//                     taskVO.setAssigneename(((User) assiginObjec).getStaffName());
//             }

            String submitTime = DateUtils.format(task.getCreateTime(), DateUtils.DATE_TIME_PATTERN);
            taskVO.setSubmitTime(submitTime);
            String querySql = "select ID_ as \"userId\",FIRST_,LAST_ as username from ACT_ID_USER WHERE ID_  ='" + hProcessInstance.getStartUserId() + "'";
            List<Map<String, Object>> list_result = wfCommonMapper.selectSQL(querySql);
            if (!list_result.isEmpty()) {
                taskVO.setStartUser(list_result.get(0).get("username").toString());
            }

            // taskVO.setSuspended(processInstance.isSuspended());
            taskVO.setBusNo(hProcessInstance.getBusinessKey());
            taskVO.setWf_param(wf_param);
            taskVO.setReturnSign(returnSign_b);
            taskVO.setProcessName(hProcessInstance.getProcessDefinitionName());
            taskVO.setBriefReport(hProcessInstance.getName());

            if (processDefinition != null) {
                taskVO.setDetailPage(processDefinition.getCategory().toString());
            }
            taskVOS.add(taskVO);

        }
        PageUtils pageUtils = new PageUtils(taskVOS, count.intValue());
        return pageUtils;
	}

	/**
	 * 别人授权给自己处理的流程
	 * @param params
	 * @return
	 */
	@Override
	public PageUtils getAuthorizationTaskList(Map<String, Object> params) {
		int page = Integer.parseInt(params.get("page") != null ? params.get("page").toString() : "0");
        int limit = Integer.parseInt(params.get("limit") != null ? params.get("limit").toString() : "0");
        String tenantId = StringUtils.isNotBlank(params.get("tenantIds")) ? params.get("tenantIds").toString().trim() : null;
        String userId = params.get("sessionUserId").toString();
        String nowString  = DateUtils.format(new Date(), "yyyy-MM-dd") + " 00:00:00";
        String endString = DateUtils.format(new Date(), "yyyy-MM-dd") + " 23:59:59";
        Map<String, Object> pp = new HashMap<String, Object>();
        pp.put("userId", userId);
        pp.put("nowString", nowString);
        pp.put("endString", endString);
        List<Map<String, Object>> delegations = delegationService.getDelegationByUserIdAndTime(pp);
        List<TaskVO> taskVOS = new LinkedList<TaskVO>();
        Map<String, TaskVO> taskVOSMap = new LinkedHashMap<String, TaskVO>();
        for (Map<String, Object> delegation : delegations) {
            List<Map<String, Object>> tasks = new ArrayList<>();
            String aTaskSql = getAuthorizationTaskListSql(tenantId, delegation.get("auth_id").toString());
            tasks = wfCommonMapper.selectSQL(aTaskSql);
            for (Map<String, Object> task : tasks) {
                TaskVO taskVO = new TaskVO();
                taskVO.setId(task.get("ID_").toString());
                taskVO.setKey(task.get("TASK_DEF_KEY_") == null ? null: task.get("TASK_DEF_KEY_").toString());
                taskVO.setName(task.get("NAME_") == null ? null: task.get("NAME_").toString());
                taskVO.setDescription(task.get("DESCRIPTION_") == null ? null: task.get("DESCRIPTION_").toString());
                taskVO.setAssignee(delegation.get("auth_id").toString());
                taskVO.setFormKey(task.get("FORM_KEY_") == null ? null: task.get("FORM_KEY_").toString());
                taskVO.setProcessId(task.get("PROC_INST_ID_").toString());
                taskVO.setProcessDefinitionId(task.get("PROC_DEF_ID_").toString());
                taskVO.setExecutionId(task.get("EXECUTION_ID_").toString());
                taskVO.setTaskDefinitionKey(task.get("TASK_DEF_KEY_").toString());
                taskVO.setBusNo(task.get("BUSINESS_KEY_") == null ? null : task.get("BUSINESS_KEY_").toString());
                taskVO.setProcessName(task.get("PROC_DEF_NAME_").toString());
                String submitTime = DateUtils.format((Date) task.get("CREATE_TIME_"), DateUtils.DATE_TIME_PATTERN);
                taskVO.setSubmitTime(submitTime);
                taskVO.setAssigneename(delegation.get("assigneename") == null ? null: delegation.get("assigneename").toString());
                taskVO.setStartUser(task.get("startUser") == null ? null: task.get("startUser").toString());
                taskVO.setBriefReport(task.get("briefReport") == null ? null: task.get("briefReport").toString());
//                taskVO.setReturnSign(returnSign_b);
                taskVO.setDetailPage(task.get("detailPage") == null ? null: task.get("detailPage").toString());
                taskVO.setReason(delegation.get("reason") == null ? null: delegation.get("reason").toString());
                //处理流程变量
                Map<String, Object> variable = taskService.getVariables(task.get("ID_").toString());
                Map<String, Object> processVariable = runtimeService.getVariables(taskVO.getExecutionId());
                Map<String, Object> wf_param = (Map<String, Object>) variable.get("wf_param");
                wf_param.putAll(processVariable);
                taskVO.setWf_param(wf_param);
                //授权处理的流程中用到：1-一般性代理、2-访问查看
                taskVO.setAuthCatagory(delegation.get("auth_catagory").toString());
                //用map去重
                taskVOSMap.put(taskVO.getId(),taskVO);
            }
        }
        taskVOS = taskVOSMap.values().stream().collect(Collectors.toList());
        List<TaskVO> taskVOSPage = new LinkedList<TaskVO>();
        int count = taskVOS.size();
        if (count == 0) {
            //不分页
        } else {
            taskVOSPage = taskVOS.subList(page > 0 ? ((page - 1) * limit) : 0, (page * limit) > count ? count : (page * limit));
        }
        PageUtils pageUtils = new PageUtils(taskVOSPage, count);
        return pageUtils;
	}
	
	private String getAuthorizationTaskListSql(String tenantId, String auth_id) {
        StringBuffer dsb = new StringBuffer();
        dsb.append("select distinct RES.*,HI.BUSINESS_KEY_,HI.START_USER_ID_,HI.NAME_ AS briefReport, DEF.KEY_ as PROC_DEF_KEY_, DEF.NAME_ as PROC_DEF_NAME_, DEF.VERSION_ as PROC_DEF_VERSION_, DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_,DEF.CATEGORY_ AS detailPage,u.LAST_ as startUser    from ACT_RU_TASK RES ");
        dsb.append(" left join ACT_RU_IDENTITYLINK I on I.TASK_ID_ = RES.ID_ ");
        dsb.append(" left join ACT_HI_PROCINST HI on RES.PROC_INST_ID_ = HI.PROC_INST_ID_");
        dsb.append(" left outer join ACT_RE_PROCDEF DEF on RES.PROC_DEF_ID_ = DEF.ID_");
        dsb.append(" left join ACT_ID_USER u on HI.START_USER_ID_=u.ID_");
        dsb.append(" WHERE  RES.TENANT_ID_ = '" + tenantId + "'");
        dsb.append(" and (RES.ASSIGNEE_ = '" + auth_id + "'");
        dsb.append(" or (RES.ASSIGNEE_ is null");
        dsb.append(" and I.TYPE_ = 'candidate' and (I.USER_ID_ = '" + auth_id + "'");
        dsb.append(" or I.GROUP_ID_ IN(");
        dsb.append(" select GROUP_ID_ from ACT_ID_MEMBERSHIP WHERE USER_ID_='" + auth_id + "'");
        dsb.append(" )))) order by RES.CREATE_TIME_ desc");
        return dsb.toString();
    }

	/**
	 * 查询当前任务节点信息
	 * @param taskId
	 * @return
	 * @throws Exception 
	 */
	@Override
	public Map<String, Object> getTaskNodeInfo(String taskId) throws Exception {
//		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		TaskFormData taskFormData = formService.getTaskFormData(taskId);
		//获取task对应的表单内容
        UserTask userTask = (UserTask)repositoryService.getBpmnModel(taskFormData.getTask().getProcessDefinitionId())
                .getFlowElement(taskFormData.getTask().getTaskDefinitionKey());
        List<FormProperty> formProperties = userTask.getFormProperties();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("task", taskFormData.getTask());
        List<Object> list = new ArrayList<Object>();
        for(org.activiti.engine.form.FormProperty pop : taskFormData.getFormProperties()) {
        	Map newMap = BeanMapUtil.bean2map(pop);
        	for(FormProperty pp : formProperties) {
        		if(pop.getName().equals(pp.getName())) {
        			newMap.put("formValues", pp.getFormValues());
        		}
        	}
        	list.add(newMap);
        }
        map.put("formProperties", list);
		return map;
	}

	/**
	 * 根据业务id查询流程处理记录
	 * @param busNo
	 * @return
	 */
	@Override
	public List<Map<String, Object>> getApproveHistoryByBusNo(String busNo) {
		List<Map<String, Object>> taskList = new LinkedList<Map<String, Object>>();
		//改为直接查结束的任务，终止的任务已处理成与正常结束的一样的道理即把终止原因存入Comment
		List<HistoricTaskInstance> list= historyService.createHistoricTaskInstanceQuery()
				.processInstanceBusinessKey(busNo).finished().orderByTaskCreateTime()
				.desc().list();
		//未结束的任务需要单独处理下审批人
		List<HistoricTaskInstance> list_unfinish= historyService.createHistoricTaskInstanceQuery()
				.processInstanceBusinessKey(busNo)
				.unfinished().orderByTaskCreateTime()
				.desc().list();

		for (int i=0;i<list_unfinish.size();i++) {

            HistoricTaskInstance hai=list_unfinish.get(i);
			List<Comment> comments = taskService.getTaskComments(hai.getId());
			Map<String, Object> _map = new LinkedHashMap<String, Object>();
			//如果是多实例可能出现多任务情况（会签）
			List<Task> tasks = taskService.createTaskQuery().processInstanceBusinessKey(busNo).list();
//			System.out.println("办理人：" + hai.getAssignee());
			//改为候选人
			List<IdentityLink> identityLinkListAll = new ArrayList<IdentityLink>();
			for(Task task : tasks) {
				List<IdentityLink> identityLinkList = taskService.getIdentityLinksForTask(task.getId());
				identityLinkListAll.addAll(identityLinkList);
			}
			List<String> listUQ = new ArrayList<String>();
			for(IdentityLink identityLink : identityLinkListAll) {
				if(identityLink.getUserId() != null) {
					listUQ.add(identityLink.getUserId());
				}
			}

			 StringBuffer inPram = new StringBuffer();
             for (String ss : listUQ) {
                 inPram.append("'" + ss + "',");
             }
             String inp = inPram.toString().substring(0, inPram.toString().length() - 1);
			String querySql = "select ID_ as \"userId\",FIRST_,LAST_ as username from ACT_ID_USER WHERE ID_ in(" + inp + ")";
            List<Map<String, Object>> assiginObjecs = wfCommonMapper.selectSQL(querySql);
			String assignee = "";
            String assigneeName="";
			Iterator <Map<String,Object>>iterator=	assiginObjecs.iterator();

			for(;iterator.hasNext();){
				Map<String,Object> assiginObjec=iterator.next();
				if(iterator.hasNext()){
					assignee+=assiginObjec.get("userId") + ",";
					assigneeName+=assiginObjec.get("username") + ",";
				}else{
					assignee+=assiginObjec.get("userId");
					assigneeName+=assiginObjec.get("username");
				}
			}

             if (assiginObjecs != null) {
                _map.put("assigneeName", assigneeName);
              }
             if (assignee != null) {
            	 _map.put("assignee", assignee);
               }
             System.out.println("活动ID:" + hai.getId());
            _map.put("actId", hai.getId());
            _map.put("activityDfId", hai.getTaskDefinitionKey());
             System.out.println("流程实例ID:" + hai.getProcessInstanceId());
            _map.put("taskId", hai.getProcessInstanceId());
             System.out.println("活动名称：" + hai.getName());
            _map.put("actName", hai.getName());
             System.out.println("开始时间：" + DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));
             _map.put("startTime", DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));

            System.out.println("结束时间：" + hai.getEndTime());
            if (hai.getEndTime() != null) {
                    _map.put("endTime", DateUtils.format(hai.getEndTime(), DateUtils.DATE_TIME_PATTERN));
                    _map.put("state", WorkflowContants.ProcessRecordState.PROCESSED.getValue());
            } else {

                _map.put("state", WorkflowContants.ProcessRecordState.PROCESSING.getValue());

            }

            //处理意见
            for (Comment cmt : comments) {
                _map.put("description", ((CommentEntity)cmt).getFullMessage());
            }

            //审批意见
            _map.put("aproveAdvice",hai.getDescription());
            taskList.add(_map);
		 }
		
		for (int i=0;i<list.size();i++) {
        	HistoricTaskInstance hai=list.get(i);
 			List<Comment> comments = taskService.getTaskComments(hai.getId());
 			Map<String, Object> _map = new LinkedHashMap<String, Object>();
 			if(hai.getAssignee() == null || "".equals(hai.getAssignee())) {
 				continue;
 			}
 			_map.put("assignee", hai.getAssignee());
// 			List<User> assiginObjecs = fSysUserAuthService.getUserByIds(Arrays.asList( hai.getAssignee().split(",")));
 			StringBuffer inPram = new StringBuffer();
            for (String ss : Arrays.asList( hai.getAssignee().split(","))) {
                inPram.append("'" + ss + "',");
            }
            String inp = inPram.toString().substring(0, inPram.toString().length() - 1);
			String querySql = "select ID_ as \"userId\",FIRST_,LAST_ as username from ACT_ID_USER WHERE ID_ in(" + inp + ")";
           List<Map<String, Object>> assiginObjecs = wfCommonMapper.selectSQL(querySql);
 			String assigneeName="";
			Iterator <Map<String,Object>>iterator=	assiginObjecs.iterator();

			for(;iterator.hasNext();){
				Map<String,Object> assiginObjec=iterator.next();
				if(iterator.hasNext()){
					if(StringUtils.isNotBlank(hai.getOwner())){
						assigneeName+=assiginObjec.get("username") + "(代)" +",";
					}else {
						assigneeName += assiginObjec.get("username") + ",";
					}
				}else{
					if(StringUtils.isNotBlank(hai.getOwner())){
						assigneeName+=assiginObjec.get("username") + "(代)";
					}else {
						assigneeName+=assiginObjec.get("username");
					}
				}
			}

             if (assiginObjecs != null) {
                _map.put("assigneeName", assigneeName);
              }

             System.out.println("活动ID:" + hai.getId());
            _map.put("actId", hai.getId());
            _map.put("activityDfId", hai.getTaskDefinitionKey());
             System.out.println("流程实例ID:" + hai.getProcessInstanceId());
            _map.put("taskId", hai.getProcessInstanceId());
             System.out.println("活动名称：" + hai.getName());
            _map.put("actName", hai.getName());
             System.out.println("开始时间：" + DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));
             _map.put("startTime", DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));

            System.out.println("结束时间：" + hai.getEndTime());
            if (hai.getEndTime() != null) {
                    _map.put("endTime", DateUtils.format(hai.getEndTime(), DateUtils.DATE_TIME_PATTERN));
                    _map.put("state", WorkflowContants.ProcessRecordState.PROCESSED.getValue());
            } else {

                _map.put("state", WorkflowContants.ProcessRecordState.PROCESSING.getValue());

            }

            //处理意见
            for (Comment cmt : comments) {
               // _map.put("description", ((CommentEntity)cmt).getMessage());
            	//解决处理意见超长展示不全问题
                _map.put("description", ((CommentEntity)cmt).getFullMessage());
            }

            //审批意见
            _map.put("aproveAdvice",hai.getDescription());
            taskList.add(_map);
        }

		 return taskList;
	}

	/**
	 * 根据流程实例id查询流程处理记录
	 * @param processId
	 * @return
	 */
	@Override
	public List<Map<String, Object>> getApproveHistoryByProcessId(String processId) {
		List<Map<String, Object>> taskList = new LinkedList<Map<String, Object>>();
		//改为直接查结束的任务，终止的任务已处理成与正常结束的一样的道理即把终止原因存入Comment
		List<HistoricTaskInstance> list= historyService.createHistoricTaskInstanceQuery().processInstanceId(processId)
				.finished().orderByTaskCreateTime().desc().list();
		//未结束的任务需要单独处理下审批人
		List<HistoricTaskInstance> list_unfinish= historyService.createHistoricTaskInstanceQuery().processInstanceId(processId)
				.unfinished().orderByTaskCreateTime().desc().list();

		for (int i=0;i<list_unfinish.size();i++) {

            HistoricTaskInstance hai=list_unfinish.get(i);
			List<Comment> comments = taskService.getTaskComments(hai.getId());
			Map<String, Object> _map = new LinkedHashMap<String, Object>();
			//如果是多实例可能出现多任务情况（会签）
			List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
//			System.out.println("办理人：" + hai.getAssignee());
			//改为候选人
			List<IdentityLink> identityLinkListAll = new ArrayList<IdentityLink>();
			for(Task task : tasks) {
				List<IdentityLink> identityLinkList = taskService.getIdentityLinksForTask(task.getId());
				identityLinkListAll.addAll(identityLinkList);
			}
			List<String> listUQ = new ArrayList<String>();
			for(IdentityLink identityLink : identityLinkListAll) {
				if(identityLink.getUserId() != null) {
					listUQ.add(identityLink.getUserId());
				}
			}

			 StringBuffer inPram = new StringBuffer();
             for (String ss : listUQ) {
                 inPram.append("'" + ss + "',");
             }
			String assignee = "";
            String assigneeName="";
            if(!listUQ.isEmpty()) {
            	String inp = inPram.toString().substring(0, inPram.toString().length() - 1);
            	String querySql = "select ID_ as \"userId\",FIRST_,LAST_ as username from ACT_ID_USER WHERE ID_ in(" + inp + ")";
            	List<Map<String, Object>> assiginObjecs = wfCommonMapper.selectSQL(querySql);
            	Iterator <Map<String,Object>>iterator=	assiginObjecs.iterator();
            	
            	for(;iterator.hasNext();){
            		Map<String,Object> assiginObjec=iterator.next();
            		if(iterator.hasNext()){
            			assignee+=assiginObjec.get("userId") + ",";
            			assigneeName+=assiginObjec.get("username") + ",";
            		}else{
            			assignee+=assiginObjec.get("userId");
            			assigneeName+=assiginObjec.get("username");
            		}
            	}
            }

             if (assigneeName != null) {
                _map.put("assigneeName", assigneeName);
              }
             if (assignee != null) {
            	 _map.put("assignee", assignee);
               }
             System.out.println("活动ID:" + hai.getId());
            _map.put("actId", hai.getId());
            _map.put("activityDfId", hai.getTaskDefinitionKey());
             System.out.println("流程实例ID:" + hai.getProcessInstanceId());
            _map.put("taskId", hai.getProcessInstanceId());
             System.out.println("活动名称：" + hai.getName());
            _map.put("actName", hai.getName());
             System.out.println("开始时间：" + DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));
             _map.put("startTime", DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));

            System.out.println("结束时间：" + hai.getEndTime());
            if (hai.getEndTime() != null) {
                    _map.put("endTime", DateUtils.format(hai.getEndTime(), DateUtils.DATE_TIME_PATTERN));
                    _map.put("state", WorkflowContants.ProcessRecordState.PROCESSED.getValue());
            } else {

                _map.put("state", WorkflowContants.ProcessRecordState.PROCESSING.getValue());

            }

            //处理意见
            for (Comment cmt : comments) {
                _map.put("description", ((CommentEntity)cmt).getFullMessage());
            }

            //审批意见
            _map.put("aproveAdvice",hai.getDescription());
            taskList.add(_map);
		 }
		
		for (int i=0;i<list.size();i++) {
        	HistoricTaskInstance hai=list.get(i);
 			List<Comment> comments = taskService.getTaskComments(hai.getId());
 			Map<String, Object> _map = new LinkedHashMap<String, Object>();
 			if(hai.getAssignee() == null || "".equals(hai.getAssignee())) {
 				continue;
 			}
 			_map.put("assignee", hai.getAssignee());
// 			List<User> assiginObjecs = fSysUserAuthService.getUserByIds(Arrays.asList( hai.getAssignee().split(",")));
 			StringBuffer inPram = new StringBuffer();
            for (String ss : Arrays.asList( hai.getAssignee().split(","))) {
                inPram.append("'" + ss + "',");
            }
            String inp = inPram.toString().substring(0, inPram.toString().length() - 1);
			String querySql = "select ID_ as \"userId\",FIRST_,LAST_ as username from ACT_ID_USER WHERE ID_ in(" + inp + ")";
           List<Map<String, Object>> assiginObjecs = wfCommonMapper.selectSQL(querySql);
 			String assigneeName="";
			Iterator <Map<String,Object>>iterator=	assiginObjecs.iterator();

			for(;iterator.hasNext();){
				Map<String,Object> assiginObjec=iterator.next();
				if(iterator.hasNext()){
					if(StringUtils.isNotBlank(hai.getOwner())){
						assigneeName+=assiginObjec.get("username") + "(代)" +",";
					}else {
						assigneeName += assiginObjec.get("username") + ",";
					}
				}else{
					if(StringUtils.isNotBlank(hai.getOwner())){
						assigneeName+=assiginObjec.get("username") + "(代)";
					}else {
						assigneeName+=assiginObjec.get("username");
					}
				}
			}

             if (assiginObjecs != null) {
                _map.put("assigneeName", assigneeName);
              }

             System.out.println("活动ID:" + hai.getId());
            _map.put("actId", hai.getId());
            _map.put("activityDfId", hai.getTaskDefinitionKey());
             System.out.println("流程实例ID:" + hai.getProcessInstanceId());
            _map.put("taskId", hai.getProcessInstanceId());
             System.out.println("活动名称：" + hai.getName());
            _map.put("actName", hai.getName());
             System.out.println("开始时间：" + DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));
             _map.put("startTime", DateUtils.format(hai.getStartTime(), DateUtils.DATE_TIME_PATTERN));

            System.out.println("结束时间：" + hai.getEndTime());
            if (hai.getEndTime() != null) {
                    _map.put("endTime", DateUtils.format(hai.getEndTime(), DateUtils.DATE_TIME_PATTERN));
                    _map.put("state", WorkflowContants.ProcessRecordState.PROCESSED.getValue());
            } else {

                _map.put("state", WorkflowContants.ProcessRecordState.PROCESSING.getValue());

            }

            //处理意见
            for (Comment cmt : comments) {
               // _map.put("description", ((CommentEntity)cmt).getMessage());
            	//解决处理意见超长展示不全问题
                _map.put("description", ((CommentEntity)cmt).getFullMessage());
            }

            //审批意见
            _map.put("aproveAdvice",hai.getDescription());
            taskList.add(_map);
        }

		 return taskList;
	}

	/**
	 * 获取可退回节点
	 * @param processId
	 * @param taskDefinitionKey
	 * @param processDefinitionId
	 * @return
	 */
	@Override
	public List<Map<String, Object>> getRetractNode(String processId, String taskDefinitionKey,
			String processDefinitionId) {
		Set<String> keys=new HashSet<String>();
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService
				.getProcessDefinition(processDefinitionId);
		// 当前节点
		ActivityImpl currentActivity=processDefinitionEntity.findActivity(taskDefinitionKey); // 根据活动id获取活动实例 
		String reBackNodeKey = currentActivity.getProperty("documentation") == null ? null : currentActivity.getProperty("documentation").toString();
		List<Map<String, Object>> taskList = new LinkedList<Map<String, Object>>();
		if(reBackNodeKey == null || "".equals(reBackNodeKey)) {
			return taskList;
		}
		String [] reBackNodeKeyArry = reBackNodeKey.split(",");

        for(String setting:reBackNodeKeyArry) {

        	List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery() // 历史相关Service
					.taskDefinitionKey(setting)
        			.processInstanceId(processId)
					.finished()
					.taskDeleteReason("completed").list();

			for (int i=0;i<tasks.size();i++) {
                HistoricTaskInstance hai=tasks.get(i);

                Map<String, Object> _map = new LinkedHashMap<String, Object>();

                System.out.println("办理人：" + hai.getAssignee());
                _map.put("assignee", hai.getAssignee());


				if(keys.contains(hai.getTaskDefinitionKey())){
					 continue;
				 }else{
					keys.add(hai.getTaskDefinitionKey());
			  	}

				System.out.println("活动ID:" + hai.getId());

				_map.put("actId", hai.getId());
				_map.put("activityDfId", hai.getTaskDefinitionKey());

				System.out.println("流程实例ID:" + hai.getProcessInstanceId());
				_map.put("taskId", hai.getProcessInstanceId());

				System.out.println("活动名称：" + hai.getName());
				_map.put("actName", hai.getName());

				taskList.add(_map);
			}
		}
		return taskList;
	}

	/**
	 * 获取审批意见
	 * @param taskId
	 * @return
	 */
	@Override
	public String getApproveAdviceByTaskId(String taskId) {
		List<Comment> comments = taskService.getTaskComments(taskId, "comment");
        if(!comments.isEmpty()){
            return comments.get(0).getFullMessage();
        }
        return "";
	}

	/**
	 * 我参与的流程
	 * @param page
	 * @param limit
	 * @param dataForm
	 * @param userId
	 * @return
	 */
	@Override
	public PageUtils queryParticipationProcessList(String page, String limit, String dataForm, String userId) {
		int pageq = Integer.parseInt(page != null ? page : "0");
        int limitq = Integer.parseInt(limit != null ? limit : "0");
        Page<Map<String, Object>> p = PageHelper.startPage(pageq, limitq);
        JSONObject obj = StringUtils.isBlank(dataForm) ? null : JSONObject.fromObject(dataForm);
        Map<String, Object> pram = new HashMap<String, Object>();
        pram.put("userId", userId);
        if (obj != null) {
            if (obj.containsKey("processName") && StringUtils.isNotBlank(obj.get("processName"))) {
                pram.put("processName", "%" + obj.getString("processName").trim() + "%");
            }
            if (obj.containsKey("briefReport") && StringUtils.isNotBlank(obj.get("briefReport"))) {
                pram.put("briefReport", "%" + obj.getString("briefReport").trim() + "%");
            }
            if (obj.containsKey("tenantIds") && StringUtils.isNotBlank(obj.get("tenantIds"))) {
                pram.put("tenantIds", obj.getString("tenantIds").trim().split(","));
            }
            //流程状态
            if (obj.containsKey("state") && StringUtils.isNotBlank(obj.get("state"))) {
                switch (obj.getString("state")) {
                    case "0":
                        pram.put("stateSql", "ins.END_TIME_ IS NULL");
                        break;
                    case "1":
                        pram.put("stateSql", "ins.END_TIME_ IS NOT NULL AND ins.DELETE_REASON_ IS NULL");
                        break;
                    case "2":
                        pram.put("stateSql", "ins.END_TIME_ IS NOT NULL AND ins.DELETE_REASON_ IS NOT NULL");
                        break;
                    default:
                        break;
                }
            }
            if (obj.containsKey("startTime") && StringUtils.isNotBlank(obj.get("startTime"))) {
                String startTime = obj.getString("startTime");
                Date dateF = null;
                Date dateT = null;
                if (!startTime.startsWith("F") && !startTime.contains("T")) { //非日期范围
                    dateT = DateUtils.setDateTwoThree(new Date());
                    dateF = DateUtils.setDateZero(DateUtils.addDateDays(dateT, -Integer.parseInt(startTime)));
                } else {//日期范围
                    List<Date> dates = DateUtils.fromDateToDate(startTime);
                    dateF = dates.get(0);
                    dateT = dates.get(1);
                }
                pram.put("startDateF", dateF);
                pram.put("startDateT", dateT);
            }
            if (obj.containsKey("endTime") && StringUtils.isNotBlank(obj.get("endTime"))) {
                String endTime = obj.getString("endTime");
                Date dateF = null;
                Date dateT = null;
                //非日期范围
                if (!endTime.startsWith("F") && !endTime.contains("T")) {
                    dateT = DateUtils.setDateTwoThree(new Date());
                    dateF = DateUtils.setDateZero(DateUtils.addDateDays(dateT, -Integer.parseInt(endTime)));
                } else {//日期范围
                    List<Date> dates = DateUtils.fromDateToDate(endTime);
                    dateF = dates.get(0);
                    dateT = dates.get(1);
                }
                pram.put("endDateF", dateF);
                pram.put("endDateT", dateT);
            }
        }
        List<Map<String, Object>> list = wfCommonMapper.getParticipantTask(pram);
        List<Map<String, Object>> lr = list.stream().map( m -> {
            if(m.get("endTime") == null){
                m.put("state", "0");
            }else if(m.get("deletereason") != null){
                m.put("state", "1");
            }else{
                m.put("state", "2");
            }
            return m;
        }).collect(Collectors.toList());
        PageUtils pageUtils = new PageUtils(p);
        pageUtils.setList(lr);
        return pageUtils;
	}

	@Override
	public PageUtils getCreateTaskList(int page, int limit, JSONObject obj, String userId) throws Exception {

        List<Map<String, Object>> result = new LinkedList<Map<String, Object>>();
//        HistoricProcessInstanceQuery processInstanceQuery = WorkFlowExecution.processEngine.
//                getHistoryService().createHistoricProcessInstanceQuery().startedBy(userId);
//        HistoricProcessInstanceQuery processInstanceCountQuery = WorkFlowExecution.processEngine.
//                getHistoryService().createHistoricProcessInstanceQuery().startedBy(userId);
//        if (obj != null && StringUtils.isNotBlank(obj.get("tenantId"))) { //2020-05-08
//            processInstanceQuery.processInstanceTenantIdLike(obj.get("tenantId").toString());
//            processInstanceCountQuery.processInstanceTenantIdLike(obj.get("tenantId").toString());
//        }

        NativeHistoricProcessInstanceQuery processInstanceQuery = historyService.createNativeHistoricProcessInstanceQuery();
        NativeHistoricProcessInstanceQuery processInstanceCount = historyService.createNativeHistoricProcessInstanceQuery();
        Long count = 0L;
        List<HistoricProcessInstance> processInstances = null;
        try {
            //组装 sql
            Map<String, String> sqlMap = assembleSql(obj, processInstanceQuery, processInstanceCount);
            processInstances = processInstanceQuery.sql(sqlMap.get("query")).parameter("userId", userId).listPage((page - 1) * limit, limit);
            count = processInstanceCount.sql(sqlMap.get("count")).parameter("userId", userId).count();

            for (HistoricProcessInstance historicProcessInstance : processInstances) {
                //执行实例  如果为空说明流程已结束
                ProcessInstanceQuery processQuery = runtimeService.createProcessInstanceQuery();

                TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(historicProcessInstance.getId());
                if (obj.get("tenantId") != null && !"".equals(obj.get("tenantId"))) {
                    processQuery.processInstanceTenantId(obj.get("tenantId").toString());
                    taskQuery.taskTenantId(obj.get("tenantId").toString());
                }

                ExecutionEntity execution = (ExecutionEntity) processQuery.processInstanceId(historicProcessInstance.getId()).singleResult();
                //当前实例的执行到哪个节点
                String activitiId = null;
                String currNode = "";
                //判断流程没结束再去获取当前节点
                if (historicProcessInstance.getEndTime() == null) {
                    List<Task> tasks = taskQuery.list();
                    List<String> nodeNames = tasks.stream().map(task -> task.getName()).collect(Collectors.toList());
                    currNode = org.apache.commons.lang3.StringUtils.join(nodeNames.toArray(), ",");
                    activitiId = tasks.isEmpty() ? null : tasks.get(0).getTaskDefinitionKey();
                } else {
                    currNode = "已结束";
                }
                ActivityImpl activityImpl_First = modelService.getFirstNode(historicProcessInstance.getProcessDefinitionId());
                Map<String, Object> map_ = new LinkedHashMap<String, Object>();
                map_.put("processId", historicProcessInstance.getId());
                map_.put("processName", historicProcessInstance.getProcessDefinitionName());
                map_.put("nodeName", currNode.toString());
                ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
                ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();
                map_.put("busNo", historicProcessInstance.getBusinessKey());
                //详情页面
                map_.put("detailPage", processDefinition.getCategory() == null ? null : processDefinition.getCategory());
                map_.put("briefReport", historicProcessInstance.getName());

                map_.put("actName", historicProcessInstance.getDescription());
                map_.put("startUserId", historicProcessInstance.getStartUserId());
                map_.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());

                map_.put("startTime", DateUtils.format(historicProcessInstance.getStartTime(), DateUtils.DATE_TIME_PATTERN));
                if (historicProcessInstance.getEndTime() != null) {
                    if (historicProcessInstance.getDeleteReason() == null) {
                        map_.put("state", "1");
                    } else {
                        map_.put("state", "2");
                    }
                    map_.put("endTime", DateUtils.format(historicProcessInstance.getEndTime(), DateUtils.DATE_TIME_PATTERN));
                } else {
                    map_.put("state", "0");
                }
    
                //当前节点是否第一个节点
                if (activitiId != null && activitiId.equals(activityImpl_First.getId())) {
                    //第一个节点
                    map_.put("firstNode", "1");
                } else {
                    map_.put("firstNode", "0");
                }

                result.add(map_);
            }
        } catch (Exception e) {
            throw e;
        }
        return new PageUtils(result, count.intValue());
	}
	
	/**
     * 我创建的流程-sql组装
     *
     * @param obj
     * @param processInstanceQuery
     * @param processInstanceCount
     */
    private Map<String, String> assembleSql(JSONObject obj, NativeHistoricProcessInstanceQuery processInstanceQuery, NativeHistoricProcessInstanceQuery processInstanceCount) {
        String[] tenantIds = StringUtils.isNotBlank(obj.get("tenantIds")) ? obj.get("tenantIds").toString().split(",") : null;

        String query_sql = "SELECT DISTINCT RES.*, DEF.KEY_ AS PROC_DEF_KEY_, DEF.NAME_ AS PROC_DEF_NAME_,DEF.VERSION_ AS PROC_DEF_VERSION_,DEF.DEPLOYMENT_ID_ AS DEPLOYMENT_ID_ " +
                "FROM ACT_HI_PROCINST RES LEFT OUTER JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_ WHERE RES.START_USER_ID_ = #{userId} ";
        String count_sql = "SELECT  COUNT(DISTINCT RES.ID_) " +
                "FROM ACT_HI_PROCINST RES LEFT OUTER JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_ WHERE RES.START_USER_ID_ = #{userId} ";
        String order_sql = " ORDER BY RES.START_TIME_ DESC";
        if (tenantIds != null) {
            String base_or_sql = "AND (RES.TENANT_ID_ LIKE CONCAT('%', #{tenantId0}, '%') ";
            for (int i = 0; i < tenantIds.length; i++) { // 多个租户ID处理
                if (i == 0) {
                    processInstanceQuery.parameter("tenantId0", tenantIds[i]);
                    processInstanceCount.parameter("tenantId0", tenantIds[i]);
                    continue;
                }
                base_or_sql = base_or_sql.concat("OR RES.TENANT_ID_ LIKE CONCAT('%', #{tenantId" + i + "}, '%')");
                processInstanceQuery.parameter("tenantId" + i, tenantIds[i]);
                processInstanceCount.parameter("tenantId" + i, tenantIds[i]);
            }
            base_or_sql = base_or_sql.concat(") ");
            query_sql = query_sql.concat(base_or_sql);
            count_sql = count_sql.concat(base_or_sql);
        }
        //查询条件
        if (obj.containsKey("processName") && StringUtils.isNotBlank(obj.get("processName"))) {
            String[] processNames = obj.getString("processName").split(",");
            String in_sql = "";
            for (int i = 0; i < processNames.length; i++) {
                in_sql = in_sql.concat("#{processName" + i + "}");
                processInstanceQuery.parameter("processName" + i, processNames[i]);
                processInstanceCount.parameter("processName" + i, processNames[i]);

                if (i < processNames.length - 1) {
                    in_sql = in_sql.concat(",");
                }
            }
            query_sql = query_sql.concat("AND DEF.NAME_ IN (" + in_sql + ")");
            count_sql = count_sql.concat("AND DEF.NAME_ IN (" + in_sql + ")");
        }
        //摘要
        if (obj.containsKey("briefReport") && StringUtils.isNotBlank(obj.get("briefReport"))) {
            query_sql = query_sql.concat("AND RES.NAME_ like #{briefReport} ");
            count_sql = count_sql.concat("AND RES.NAME_ like #{briefReport} ");
            processInstanceQuery.parameter("briefReport", "%" + obj.getString("briefReport").trim() + "%");
            processInstanceCount.parameter("briefReport", "%" + obj.getString("briefReport").trim() + "%");
        }
        //流程状态
        if (obj.containsKey("state") && StringUtils.isNotBlank(obj.getString("state"))) {
            switch (obj.getString(("state"))) {
                case "0":
                    query_sql = query_sql.concat(" AND RES.END_TIME_ IS NULL");
                    count_sql = count_sql.concat(" AND RES.END_TIME_ IS NULL");
                    break;
                case "1":
                    query_sql = query_sql.concat(" AND RES.END_TIME_ IS NOT NULL AND RES.DELETE_REASON_ IS NULL ");
                    count_sql = count_sql.concat(" AND RES.END_TIME_ IS NOT NULL AND RES.DELETE_REASON_ IS NULL ");
                    break;
                case "2":
                    query_sql = query_sql.concat(" AND RES.END_TIME_ IS NOT NULL AND RES.DELETE_REASON_ IS NOT NULL ");
                    count_sql = count_sql.concat(" AND RES.END_TIME_ IS NOT NULL AND RES.DELETE_REASON_ IS NOT NULL ");
                default:
                    break;
            }
        }
        //开始时间
        if (obj.containsKey("startTime") && StringUtils.isNotBlank(obj.getString("startTime"))) {
            String startTime = obj.getString("startTime");
            Date dateF = null;
            Date dateT = null;
            //非日期范围
            if (!startTime.startsWith("F") && !startTime.contains("T")) {
                dateT = DateUtils.setDateTwoThree(new Date());
                dateF = DateUtils.setDateZero(DateUtils.addDateDays(dateT, -Integer.parseInt(startTime)));
            } else {//日期范围
                List<Date> dates = DateUtils.fromDateToDate(startTime);
                dateF = dates.get(0);
                dateT = dates.get(1);
            }
            query_sql = query_sql.concat(" AND RES.START_TIME_ BETWEEN #{startDateF} AND #{startDateT}");
            count_sql = count_sql.concat(" AND RES.START_TIME_ BETWEEN #{startDateF} AND #{startDateT}");
            processInstanceQuery.parameter("startDateF", dateF);
            processInstanceQuery.parameter("startDateT", dateT);
            processInstanceCount.parameter("startDateF", dateF);
            processInstanceCount.parameter("startDateT", dateT);
        }
        //结束时间
        if (obj.containsKey("endTime") && StringUtils.isNotBlank(obj.getString("endTime"))) {
            String endTime = obj.getString("endTime");
            Date dateF = null;
            Date dateT = null;
            //非日期范围
            if (!endTime.startsWith("F") && !endTime.contains("T")) {
                dateT = DateUtils.setDateTwoThree(new Date());
                dateF = DateUtils.setDateZero(DateUtils.addDateDays(dateT, -Integer.parseInt(endTime)));
            } else {                                                   //日期范围
                List<Date> dates = DateUtils.fromDateToDate(endTime);
                dateF = dates.get(0);
                dateT = dates.get(1);
            }
            query_sql = query_sql.concat(" AND RES.END_TIME_ BETWEEN #{endDateF} AND #{endDateT}");
            count_sql = count_sql.concat(" AND RES.END_TIME_ BETWEEN #{endDateF} AND #{endDateT}");
            processInstanceQuery.parameter("endDateF", dateF);
            processInstanceQuery.parameter("endDateT", dateT);
            processInstanceCount.parameter("endDateF", dateF);
            processInstanceCount.parameter("endDateT", dateT);
        }
        query_sql = query_sql.concat(order_sql);
        Map<String, String> queryMap = new HashMap<>(2);
        queryMap.put("query", query_sql);
        queryMap.put("count", count_sql);
        return queryMap;
    }

    /**
	 * 根据流程实例获取最后一个执行节点的表单信息（用于展现动态表单的详情页面）
	 * @param processId
	 * @return
     * @throws Exception 
	 */
	@Override
	public Map<String, Object> getProcessInsLastNodeInfo(String processId) throws Exception {
		
		List<HistoricTaskInstance> listProcess = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId).includeProcessVariables().includeTaskLocalVariables().orderByTaskCreateTime().desc().list();
		Map<String, Object> var = listProcess.get(0).getProcessVariables();
		Map<String, Object> varLocal = listProcess.get(0).getTaskLocalVariables();
//		TaskFormData taskFormData = formService.getTaskFormData(listProcess.get(0).getId());
		//获取task对应的表单内容
        UserTask userTask = (UserTask)repositoryService.getBpmnModel(listProcess.get(0).getProcessDefinitionId())
                .getFlowElement(listProcess.get(0).getTaskDefinitionKey());
        List<FormProperty> formProperties = userTask.getFormProperties();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("task", listProcess.get(0));
        List<Object> list = new ArrayList<Object>();
        Map<String, Object> varMap = varLocal.isEmpty() ? (Map<String, Object>)var.get("formProperties") : (Map<String, Object>)varLocal.get("formProperties");
        for(String key : varMap.keySet()) {
        	Map<String, Object> newMap = new LinkedHashMap<String, Object>();
        	newMap.put("id", key);
        	newMap.put("value", varMap.get(key));
        	for(FormProperty pp : formProperties) {
        		if(key.equals(pp.getId())) {
        			newMap.put("name", pp.getName());
        			newMap.put("type", pp.getType());
        			newMap.put("isReadable", pp.isReadable());
        			newMap.put("isRequired", pp.isRequired());
        			newMap.put("isWriteable", pp.isWriteable());
        			newMap.put("formValues", pp.getFormValues());
        		}
        	}
        	list.add(newMap);
        }
        map.put("formProperties", list);
		return map;
	}
	
	/**
     * 根据流程实例id查询当前用户参与过的节点，不包含撤回和终止的节点
     * @param processid 流程实例id
     * @param user      操作用户
     * @return
     */
    @Override
    public List<Map<String, Object>> getCanRecallNode(String processid, User user) {
        //所有参与过的流程
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processid).finished().or().taskAssignee(user.getId()).taskOwner(user.getId()).endOr().list();
        //当前任务
        List<Task> nowTasks = taskService.createTaskQuery().processInstanceId(processid).list();
        //当前任务所处节点
        Map<String, String> nowTaskDefKeys = new HashMap<String, String>();
        for(Task task : nowTasks){
            nowTaskDefKeys.put(task.getTaskDefinitionKey(), task.getTaskDefinitionKey());
        }
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        Map<String, Object> mapTemp = new HashMap<String, Object>();//去重用的
        for(HistoricTaskInstance his : historicTaskInstances){
            // 过滤掉撤销、终止和当前任务所处节点的记录
            if(!WorkflowContants.ProcessResult.RECALL.getValue().equals(his.getDescription()) && !WorkflowContants.ProcessResult.TERMINATE.getValue().equals(his.getDescription()) && !nowTaskDefKeys.containsKey(his.getTaskDefinitionKey())){
                mapTemp.put(his.getTaskDefinitionKey(), his.getName());
            }
        }
        
        for(String key : mapTemp.keySet()){
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("key", key);
            map.put("name", mapTemp.get(key));
            list.add(map);
        }
        return list;
    }
    
    /**
     * 参与人撤回流程
     *
     * @param params {'processId': 流程实例id,
     *               *  'recallNodeKey': 要撤回的节点key,
     *               *  'deleteReason': 撤回原因
     *               *  }
     * @param user
     * @param system
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recallMaster(Map<String, Object> params, User user, User system) throws Exception{
        String processid = params.get("processId") != null ? params.get("processId").toString() : "";
        String recallNodeKey = params.get("recallNodeKey") != null ? params.get("recallNodeKey").toString() : "";
        String deleteReason = params.get("deleteReason") != null ? params.get("deleteReason").toString() : "";
        if(StringUtils.isBlank(processid) || StringUtils.isBlank(recallNodeKey) || StringUtils.isBlank(deleteReason)){
            throw new BusinessException("参数不正确");
        }
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().unfinished().processInstanceId(processid).singleResult();
        if (historicProcessInstance == null) {
            throw new BusinessException("流程已结束，无法撤回！");
        }
        ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
        if (definitionEntity == null) {
            throw new BusinessException("未查询到关联流程，无法撤回！");
        }
    
        //当前任务
        List<Task> oldTasks = taskService.createTaskQuery().processInstanceId(processid).list();
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("assigne", user.getId());
        RollbackTaskCmd rCmd = new RollbackTaskCmd(oldTasks.get(0).getId(), recallNodeKey, user.getId(), variables, deleteReason, WorkflowContants.ProcessResult.RECALL.getValue(), false);
        managerService.executeCommand(rCmd);
        ActivityImpl recallActivity = definitionEntity.findActivity(recallNodeKey);
        Map<String, Object> mapProperties = recallActivity.getProperties();
        if (mapProperties.containsKey("multiInstance")) {
            //流程多实例，找到任意一条任务检出，删除其他任务
            List<Task> newtasks = taskService.createTaskQuery().processInstanceId(processid).list();
            if(!newtasks.isEmpty()){
                taskService.claim(newtasks.get(0).getId(), user.getId());//检出第一条任务
                for (int i = 1; i < newtasks.size(); i++) {
                    taskService.claim(newtasks.get(i).getId(), system.getId());//检出任务至一个不存在的用户名下
                    taskService.complete(newtasks.get(i).getId());//完成该任务，查询时候过滤这些数据
                }
            }
        }else{
            //获取新任务,设置候选人（谁撤回的谁待办）
            List<Task> newtasks = taskService.createTaskQuery().processInstanceId(processid).list();
            for (Task newtask : newtasks) {
                taskService.claim(newtask.getId(), user.getId());//检出任务
            }
        }
    }
    
    /**
     * 发起人撤回
     *
     * @param processid 流程实例id
     * @param user 操作用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restartByCreater(String processid, User user) throws Exception {
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                                                                   .processInstanceId(processid).unfinished().list();
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("assigne", user.getId());
        if (historicTaskInstances.size() < 1) {
            throw new BusinessException("任务已结束，不能进行回退操作！");
        }
        //当前任务
        List<Task> oldTasks = taskService.createTaskQuery().processInstanceId(processid).list();
        ActivityImpl activityImpl_First = modelService.getFirstNode(historicTaskInstances.get(0).getProcessDefinitionId());
        if (activityImpl_First == null) {
            throw new BusinessException("撤回错误！");
        }
        /*NodeJumpTaskCmd cmd = new NodeJumpTaskCmd(historicTaskInstances.get(0).getExecutionId(), activityImpl_First, variables,
                null, "发起人撤回", WorkflowContants.ProcessResult.RECALL.getValue(), user.getId());*/
        RollbackTaskCmd rCmd = new RollbackTaskCmd(oldTasks.get(0).getId(), activityImpl_First.getId(), user.getId(), variables, "发起人撤回", WorkflowContants.ProcessResult.RECALL.getValue(), true);
        managerService.executeCommand(rCmd);
        //获取新任务,设置处理人，发起人撤回，直接指定当前人为处理人
        TaskQuery taskQuery = taskService.createTaskQuery();
        List<Task> newtasks = taskQuery.executionId(historicTaskInstances.get(0).getExecutionId()).list();
        for (Task newtask : newtasks) {
            taskService.setAssignee(newtask.getId(), user.getId());
        }
        /*if ("1".equals(cmd.code)) {
            throw new BusinessException(cmd.msg);
        }*/
    }

    /**
     * 流程查询、分页,只查询自己租户的
     * @param params
     * @param user 
     * @return
     */
	@Override
	public PageUtils allProcessList(Map<String, Object> params, User user) {
        int page = Integer.parseInt(params.get("page").toString());
        int limit = Integer.parseInt(params.get("limit").toString());
        String startUseName = params.get("startUseName") != null ? params.get("startUseName").toString() : "";
        String processName = params.get("processName") != null ? params.get("processName").toString() : "";
        String oper_time_start = params.get("oper_time_start") != null ? params.get("oper_time_start").toString() : "";
        String oper_time_end = params.get("oper_time_end") != null ? params.get("oper_time_end").toString() : "";
        String processState = params.get("processState") != null ? params.get("processState").toString() : "";
        String description = params.get("description") != null ? params.get("description").toString() : "";

        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        query.processInstanceTenantId(user.getTenantId());
        if (!"".equals(startUseName)) {
            query.variableValueLike("wf_startUserName", "%" + startUseName.trim() + "%");
        }

        if (!"".equals(processName)) {
            query.processDefinitionName(processName);
        }

        if (!"".equals(description)) {
            query.processInstanceNameLike("%" + description + "%");
        }
        try {
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if (!"".equals(oper_time_start)) {
                query.startedAfter(format.parse(oper_time_start + " 00:00:00"));
            }
            if (!"".equals(oper_time_end)) {
                query.startedBefore(format.parse(oper_time_end + " 23:59:59"));
            }
        } catch (Exception e) {
            throw new BusinessException("日期格式不对");
        }
        if (WorkflowContants.ProcessInstanceState.RUN.getValue().equals(processState)) {
            query.unfinished();
        } else if (WorkflowContants.ProcessInstanceState.END.getValue().equals(processState)) {
            query.finished();
            query.notDeleted();
        } else if (WorkflowContants.ProcessInstanceState.TERMINATED.getValue().equals(processState)) {
            query.deleted();
        }

        List<HistoricProcessInstance> list = query.orderByProcessInstanceStartTime().desc() // 创建历史流程实例查询
                .listPage((page - 1) * limit, limit);

        List<HistoryProcessVo> hpvList = new ArrayList<HistoryProcessVo>();
        for (HistoricProcessInstance hpi : list) {
            HistoryProcessVo historyProcessVo = new HistoryProcessVo((HistoricProcessInstanceEntity) hpi);
            List<Task> actTasks = taskService.createTaskQuery().processInstanceId(hpi.getId()).list();
            String actNodeName = actTasks.stream().map(e -> e.getName()).collect(Collectors.joining(","));
            historyProcessVo.setNodeName(actNodeName);
            historyProcessVo.setDescription(hpi.getName());
            if (historyProcessVo.getStartUserId() != null) {
                org.activiti.engine.identity.User assiginObjec = identityService.createUserQuery()
                        .userId(historyProcessVo.getStartUserId()).singleResult();
                if (assiginObjec != null) {
                    historyProcessVo.setStartUserName(assiginObjec.getLastName());
                }
            }
            List<String> useridq = new ArrayList<>();
            List<List<String>> userIds = actTasks.stream().map(e -> {
                List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(e.getId());
                List<String> s = identityLinks.stream().map(m -> m.getUserId()).collect(Collectors.toList());
                useridq.addAll(s);
                return s;
            }).collect(Collectors.toList());
            if (!useridq.isEmpty()) {
                NativeUserQuery naquery = identityService.createNativeUserQuery();
                String sqlT = "select * from ACT_ID_USER where ID_ in(";
                for (int c = 0; c < useridq.size(); c++) {
                    sqlT = sqlT.concat("#{useridq" + c + "}");
                    if (c != useridq.size() - 1) {
                        sqlT = sqlT.concat(",");
                    }
                    naquery.parameter("useridq" + c, useridq.get(c));
                }
                sqlT = sqlT.concat(")");
                String curUsernames = naquery.sql(sqlT).list().stream().map(o -> o.getLastName())
                        .collect(Collectors.joining(","));
                historyProcessVo.setCurUserName(curUsernames);
            }
            hpvList.add(historyProcessVo);
        }
        int count = (int) query.count();
        PageUtils pageUtils = new PageUtils(hpvList, count);
		return pageUtils;
	}

	/**
	 * 终止流程
	 * @param processid
	 * @param deleteReason
	 * @param user
	 */
	@Override
    @Transactional(rollbackFor = Exception.class)
	public void deleteProcess(String processid, String deleteReason, User user) {
		HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processid)
                .finished().singleResult();
        if (historicProcessInstance != null) {
        	throw new BusinessException("流程已结束，不能操作！");
        }
        runtimeService.setVariable(processid, "wf_deleteUserId", user.getId());
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processid).singleResult();
        Execution execution = runtimeService.createExecutionQuery().processInstanceId(processid).executionId(processid).singleResult();
        ActivitiEvent event = ActivitiEventBuilder.createEvent(ActivitiEventType.ENTITY_SUSPENDED, execution.getId(), processInstance.getId(), processInstance.getProcessDefinitionId());
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processid).list();
        for(Task task : tasks){
            task.setDescription(WorkflowContants.ProcessResult.TERMINATE.getValue());
            // 添加删除原因
            taskService.addComment(task.getId(), processInstance.getId(), deleteReason);
            taskService.setAssignee(task.getId(), user.getId());
            // taskService.saveTask(task);
        }
        runtimeService.deleteProcessInstance(processid, deleteReason);
        runtimeService.dispatchEvent(event);
	}

	/**
     * 流程退回
     * 
     * @param taskId        当前任务id
     * @param activityDfId  退回节点
     * @param userId        要退回节点的审批人assignee
     * @param user          操作人
     * @param approveAdvice 处理结果
     * @param discicription 处理意见
     * @param wfParam       流程变量
     */
	@Override
    @Transactional(rollbackFor = Exception.class)
	public void rejectTaskToOld(String taskId, String activityDfId, String userId, User user, String approveAdvice, String discicription,
            JSONObject wfParam) {
		Map<String, Object> variables = new HashMap<String, Object>();
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
                .taskId(taskId).finished().singleResult();
        if (historicTaskInstance != null) {
        	throw new BusinessException("任务已结束，不能进行回退操作！");
        }
        if (activityDfId == null || "".equals(activityDfId)) {
        	throw new BusinessException("回退目标节点不能为空！");
        }
        long count = taskService.createTaskQuery().taskId(taskId).count();
        if (count == 0) {
        	throw new BusinessException("要驳回的任务已不存在！");
        }

        HistoricTaskInstance historicTaskInstance_curent = historyService.createHistoricTaskInstanceQuery().taskId(taskId).unfinished().singleResult();

        if (user != null) {
            taskService.setAssignee(taskId, user.getId());
        }

        Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();

        ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(currentTask.getProcessDefinitionId());

        String instanceId = currentTask.getProcessInstanceId();

        ActivityImpl activityImpl = definitionEntity.findActivity(activityDfId);

        if (activityImpl == null) {
        	throw new BusinessException("要驳回的任务已不存在！");
        }
        if(wfParam != null){
            for(Object key : wfParam.keySet()){
                Object keyvalue = wfParam.get(key);
                variables.put((String)key, keyvalue);
            }
        }
        Set<String> allCandidateUser = new HashSet<String>();
        managerService.executeCommand(new RollbackTaskCmd(taskId, activityDfId, user.getId(), variables, discicription, WorkflowContants.ProcessResult.BACK.getValue(), false));
		
        //获取新任务,设置候选人（如果是策略需要重新获取候选人）
        List<Task> newtasks = taskService.createTaskQuery().processInstanceId(instanceId).list();
        HistoricProcessInstance hProcessInstance = historyService.createHistoricProcessInstanceQuery().unfinished().
                processInstanceId(newtasks.get(0).getProcessInstanceId()).singleResult();
        for (Task newtask : newtasks) {
            allCandidateUser.addAll(addCandidateUser(hProcessInstance.getStartUserId(), newtask));
        }
	}

	/**
     * 发起人撤回,根据业务主键撤回
     * @param busNo 业务主键
     * @param user 操作用户
	 * @throws Exception 
     */
	@Override
    @Transactional(rollbackFor = Exception.class)
	public void restartByBusNo(String busNo, User user) throws Exception {
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(busNo).singleResult();
		if(processInstance == null) {
			throw new BusinessException("流程不存在！");
		}
		restartByCreater(processInstance.getId(), user);
		
	}

	/**
     * 根据业务id查询用户对流程的操作权限
     * @param userId 用户id
     * @param busId 业务id数组
     * @param tenantId 租户
     * @return
     */
	@Override
	public Map<String, Map<String, Object>> getUserDelStatusByBusKey(String userId, String[] busId, String tenantId) {
		Map<String, Map<String, Object>> map = new HashMap<String, Map<String, Object>>();
        String[] psTask = { "id", "name", "owner", "processInstanceId", "processDefinitionId", "delegationState", "assignee",
                "category", "createTime", "description", "dueDate", "executionId", "formKey", "parentTaskId",
                "priority", "processVariables", "taskDefinitionKey", "taskLocalVariables", "tenantId"};
        String[] psProcess = { "processDefinitionId", "startUserId", "endTime", "id", "name", "businessKey", "deleteReason",
                "processDefinitionName", "startTime", "description", "deploymentId", "processDefinitionKey", "tenantId",
                "durationInMillis", "processDefinitionVersion", "processVariables", "startActivityId", "superProcessInstanceId"};
        for(String buskey : busId){
            // 自己的流程
            List<Task> tasksPer = taskService.createTaskQuery().taskCandidateOrAssigned(userId).processInstanceBusinessKey(buskey).taskTenantId(tenantId).list();
            if(tasksPer.size() > 0){
                Map<String, Object> taskMap = ObjectUtils.obj2map(tasksPer.get(0), psTask);
                Map<String, Object> mng = new HashMap<String, Object>();
                mng.put("ownDel", "1");//自己的流程可处理
                mng.put("authDel", "0");//非授权给自己的流程
                mng.put("rejectDel", "0");//即使我发起的流程也不用撤回
                mng.put("task", taskMap);
                map.put(buskey, mng);
                continue;
            }else{
                List<Delegation> Delegations = delegationService.getDelegationByUserId(userId);
                for (Delegation delegation : Delegations) {
                    List<Task> tenant_list = taskService.createTaskQuery().taskTenantIdLike(tenantId).taskCandidateOrAssigned(delegation.getAuthId()).processInstanceBusinessKey(buskey).list();
                    if(tenant_list.size() > 0){
                        Map<String, Object> taskMap = ObjectUtils.obj2map(tenant_list.get(0), psTask);
                        Map<String, Object> mng = new HashMap<String, Object>();
                        mng.put("ownDel", "0");//非自己的流程
                        mng.put("authDel", "1");//授权给自己的流程可处理
                        mng.put("rejectDel", "0");//即使我发起的流程也不用撤回
                        mng.put("task", taskMap);
                        map.put(buskey, mng);
                    }
                }
                if(map.containsKey(buskey)){
                    continue;
                }
            }
            if(!map.containsKey(buskey)){
                //查我发起且没结束的流程可撤回，调用com.rf.cloud.annuity.workflow.controller.TaskController.restartByBusNo根据业务id撤回
                List<HistoricProcessInstance> historicProcessInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(buskey).processInstanceTenantId(tenantId).startedBy(userId).unfinished().list();
                if(historicProcessInstanceList.size() > 0){
                    Map<String, Object> processMap = ObjectUtils.obj2map(historicProcessInstanceList.get(0), psProcess);
                    Map<String, Object> mng = new HashMap<String, Object>();
                    mng.put("ownDel", "0");//非自己的流程
                    mng.put("authDel", "0");//非授权给自己的流程
                    mng.put("rejectDel", "1");//我发起的流程可撤回
                    mng.put("processInstance", processMap);
                    map.put(buskey, mng);
                    continue;
                }
                List<HistoricProcessInstance> historicProcessInstanceListFinish = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(buskey).processInstanceTenantId(tenantId).list();
                if(historicProcessInstanceListFinish.size() > 0){
                    Map<String, Object> processMap = ObjectUtils.obj2map(historicProcessInstanceListFinish.get(0), psProcess);
                    Map<String, Object> mng = new HashMap<String, Object>();
                    mng.put("ownDel", "0");//非自己的流程
                    mng.put("authDel", "0");//非授权给自己的流程
                    mng.put("rejectDel", "0");//非我发起的流程或者流程已结束
                    mng.put("processInstance", historicProcessInstanceListFinish.get(0));
                    map.put(buskey, mng);
                    continue;
                }
            }
        }
        return map;
	}

	/**
     * 暂存审批意见
     * @param userId 用户id
     * @param taskId 任务id
     * @param approveAdvice 审批意见
     * @param authCatagory 是否代理
     * @param owner 授权人，authCatagory是‘1’时候
     */
	@Override
	public void saveApproveAdvice(String userId, String taskId, String approveAdvice, String authCatagory, String owner) {
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(StringUtils.isBlank(task.getAssignee())){
            //受理人为空的先检出再改审批意见
            taskService.claim(taskId, userId);
            if("1".equals(authCatagory)){
                //如果是代理的情况，把拥有者改为授权人
                taskService.setOwner(taskId, owner);
            }
            taskService.addComment(task.getId(), task.getProcessInstanceId(), approveAdvice);
        } else if(userId.equals(task.getAssignee())){
            //受理人是自己的修改审批意见
            List<Comment> comments = taskService.getTaskComments(taskId, "comment");
            for(Comment comment : comments){
                taskService.deleteComment(comment.getId());
            }
            taskService.addComment(task.getId(), task.getProcessInstanceId(), approveAdvice);
        } else{
            //受理人不是自己的不让修改
            throw new BusinessException("该任务已被别人处理");
        }
	}

    /**
     * 根据当前流程任务id查询流程变量
     * 
     * @param taskId
     * @return
     */
    @Override
    public Map<String, Object> getTaskParamByTaskId(String taskId) {
        return taskService.getVariables(taskId);
    }

    @Override
    public void addAssignee(String checkProcessId, List<String> ids) {
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(checkProcessId).list();
        for (Task t : tasks) {
            for (String id : ids) {
                taskService.addCandidateUser(t.getId(), id);
            }
        }
    }

    /**
     * 获取可退回节点
     * 
     * @param taskId
     * @return
     */
    @Override
    public List<Map<String, Object>> getRetractNodeByTaskId(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        Set<String> keys = new HashSet<String>();
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService
                .getProcessDefinition(task.getProcessDefinitionId());
        // 当前节点
        ActivityImpl currentActivity = processDefinitionEntity.findActivity(task.getTaskDefinitionKey()); // 根据活动id获取活动实例
        String reBackNodeKey = currentActivity.getProperty("documentation") == null ? null
                : currentActivity.getProperty("documentation").toString();
        List<Map<String, Object>> taskList = new LinkedList<Map<String, Object>>();
        if (reBackNodeKey == null || "".equals(reBackNodeKey)) {
            return taskList;
        }
        String[] reBackNodeKeyArry = reBackNodeKey.split(",");

        for (String setting : reBackNodeKeyArry) {

            List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery() // 历史相关Service
                    .taskDefinitionKey(setting)
                    .processInstanceId(task.getProcessInstanceId())
                    .finished()
                    .taskDeleteReason("completed").list();

            for (int i = 0; i < tasks.size(); i++) {
                HistoricTaskInstance hai = tasks.get(i);
                Map<String, Object> _map = new LinkedHashMap<String, Object>();
                _map.put("assignee", hai.getAssignee());
                if (keys.contains(hai.getTaskDefinitionKey())) {
                    continue;
                } else {
                    keys.add(hai.getTaskDefinitionKey());
                }
                _map.put("actId", hai.getId());
                _map.put("activityDfId", hai.getTaskDefinitionKey());
                _map.put("taskId", hai.getProcessInstanceId());
                _map.put("actName", hai.getName());
                taskList.add(_map);
            }
        }
        return taskList;
    }
}
